package cn.thoughtworks.school.programCenter.services;

import cn.thoughtworks.school.programCenter.entities.*;
import cn.thoughtworks.school.programCenter.entities.commands.CreateUserOrganization;
import cn.thoughtworks.school.programCenter.entities.commands.CreateUserRoleCommand;
import cn.thoughtworks.school.programCenter.entities.dto.UserDto;
import cn.thoughtworks.school.programCenter.exceptions.BusinessException;
import cn.thoughtworks.school.programCenter.feign.UserCenterFeign;
import cn.thoughtworks.school.programCenter.repositories.ProgramRepository;
import cn.thoughtworks.school.programCenter.repositories.UserGroupRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserCenterService {
  private final static Integer TUTOR_ROLE = 2;
  @Autowired
  private UserGroupRepository userGroupRepository;
  @Autowired
  private UserCenterFeign userCenterFeign;
  @Autowired
  private ProgramRepository programRepository;
  @Autowired
  private OrganizationService organizationService;
  @Autowired
  private UserExcelImportService userExcelImportService;

  public ResponseEntity getUserInfo(Long userId) {
    return userCenterFeign.getUserById(userId);
  }

  public List getUsersByIds(String ids) {
    if (ids.equals("")) {
      return new ArrayList();
    }
    List<Map> users = userCenterFeign.getUsersByIds(ids).getBody();
    return users.stream().map(item -> {
      item.remove("password");
      return item;
    }).collect(Collectors.toList());
  }

  public ResponseEntity<List<Map>> getUserByNameOrEmail(String nameOrEmail) {
    return userCenterFeign.getUserByUserNameOrEmail(nameOrEmail);

  }

  public Map getUserByName(String name) {
    return userCenterFeign.getUserByUsername(name).getBody();
  }

  public ResponseEntity<List<Map>> getUsersByUsername(String username) {
    return userCenterFeign.getUserByUserNameOrEmail(username);
  }

  public void addTutorRole(TutorProgram tutorProgram) throws BusinessException {
    Long tutorId = tutorProgram.getTutorId();
    Long organizationId = programRepository.findById(tutorProgram.getProgramId())
      .orElseThrow(() -> new BusinessException("Current program is not exist"))
      .getOrganizationId();
    Map data = new HashMap();
    data.put("userId", tutorId);
    data.put("role", TUTOR_ROLE);
    data.put("organizationId", organizationId);

    userCenterFeign.addRole(data);
  }

  public List<Map> getUsersByUsernameOrEmail(List usernameOrEmails) {
    Map condition = new HashMap();
    condition.put("usernameOrEmail", usernameOrEmails);

    return userCenterFeign.searchUsersByConditions(condition).getBody();
  }

  public List getUsers(String studentIds, Long programId) {
    List result = new ArrayList();
    List<Map> users = getUsersByIds(studentIds);
    users.forEach(item -> {
      Map temp = new HashMap();
      temp.put("id", item.get("id"));
      temp.put("name", item.get("name"));
      temp.put("mobilePhone", item.get("mobilePhone"));
      temp.put("email", item.get("email"));
      temp.put("username", item.get("username"));
      List<Group> groups = userGroupRepository.findByProgramIdAndStudentId(programId, Long.valueOf(item.get("id").toString()))
        .stream().map(UserGroup::getGroup).collect(Collectors.toList());
      temp.put("groups", groups);
      result.add(temp);
    });

    return result;
  }

  public List<UserRole> getUserRolesByCondition(Long organizationId, Map condition) {
    List<Map> userDetails;
    List<String> userIds;

    if (needFoundAll(condition)) {
      userIds = getNeedToFindUserIds(organizationId);
    } else {
      userDetails = userCenterFeign.searchUsersByConditionsAndOrganizationId(organizationId, condition);
      userIds = userDetails.stream().map(userDetail -> userDetail.get("id").toString())
        .collect(Collectors.toList());
    }
    if (userIds.size() == 0) {
      return new ArrayList<>();
    }
    return userCenterFeign.getUsersByOrganizationIdAndIds(organizationId, String.join(",", userIds));
  }

  private boolean needFoundAll(Map condition) {
    List usernameOrEmails = (List) condition.get("usernameOrEmail");
    return usernameOrEmails.size() == 0;
  }

  private List<String> getNeedToFindUserIds(Long organizationId) {
    List<Map> userRoles = userCenterFeign.getUserRolesByOrganizationId(organizationId);
    userRoles = userRoles.stream().filter(userRole -> {
      Integer role = (Integer) userRole.get("role");
      return !role.equals(TUTOR_ROLE);
    }).collect(Collectors.toList());

    return userRoles.stream().map(userRole ->
      userRole.get("userId").toString()).distinct().collect(Collectors.toList());
  }

  public void updateUserRole(CreateUserRoleCommand createUserRoleCommand) {
    if ("DELETE".equals(createUserRoleCommand.getType())) {
      deleteUserRole(createUserRoleCommand);
    } else {
      addUserRole(createUserRoleCommand);
    }
    organizationService.addUserOrganization(createUserRoleCommand.getOrganizationId(), createUserRoleCommand.getUserId());
  }

  private void addUserRole(CreateUserRoleCommand createUserRoleCommand) {
    Map userRole = new HashMap();
    userRole.put("userId", createUserRoleCommand.getUserId());
    userRole.put("role", createUserRoleCommand.getRoleNumber());
    userRole.put("organizationId", createUserRoleCommand.getOrganizationId());

    userCenterFeign.addRole(userRole);
  }

  private void deleteUserRole(CreateUserRoleCommand createUserRoleCommand) {
    userCenterFeign.deleteUserRole(createUserRoleCommand.getOrganizationId(),createUserRoleCommand.getUserId(), createUserRoleCommand.getRoleNumber());
  }

  public Long getUserCurrentOrganizationId(Long id) {
    Map user = userCenterFeign.getUserById(id).getBody();
    return Long.valueOf(user.get("currentOrganizationId").toString());
  }

  public void updateUserCurrentOrganizationId(Long userId, CreateUserOrganization createUserOrganization) {
    createUserOrganization.setUserId(userId);
    userCenterFeign.updateUserCurrentOrganizationId(createUserOrganization);
  }

  public List<Map> findUserRolesByUserId(Long userId) {
    return userCenterFeign.findUserRolesByUserId(userId);
  }

  public void importUsers(MultipartFile file, User current) throws IOException, BusinessException {
      userExcelImportService.init(file);
      List<UserDto> userDtos = userExcelImportService.parseUsers(current);

      userCenterFeign.importUsers(userDtos);
  }
}
